<?php

namespace app\api\controller\v13;

use app\api\controller\v2\Auth;
use app\common\cachemodel\Fortune;
use app\common\cachemodel\NatalReport;
use app\common\cachemodel\Orders as OrdersCacheModel;
use app\common\cachemodel\OrdersGoods;
use app\common\cachemodel\OrdersLib;
use app\common\cachemodel\Recode;
use app\common\cachemodel\UserCoupon;
use app\common\cachemodel\ZlActivePrizeNumIncRecord;
use app\common\cachemodel\ZlcrContentCheck;
use app\common\cachemodel\ZlcrCustomReportGoods;
use app\common\cachemodel\ZlcrCustomReportQuestion;
use app\common\cachemodel\ZlcrCustomReportQuestionInfo;
use app\common\cachemodel\ZlSynastryReport;
use app\common\cachemodel\ZlTarotRecords;
use app\common\lib\exception\ApiException;
use app\common\lib\PushQueue;
use app\common\lib\Util;
use Exception;
use think\Db;
use think\Log;
use think\response\Json;

/**
 * 1.9.6订单控制器
 * Class Orders
 * @package app\api\controller\v13
 */
class Orders extends Auth
{
    public $msg;

    /**
     * 检测用户是否绑定手机号
     * @return bool
     * @throws ApiException
     */
    private function CheckUserTel()
    {
        // TODO 暂时关闭下单验证手机号逻辑
//        if (!$this->user['tel'])
//        {
//            throw new ApiException('请绑定手机号后进行购买', 200, 407);
//        }
        return true;
    }

    /**
     * 接口，下单
     * order_type 1=>校准生辰,2=>日运,3=>月运,4=>年运,5=>幸运之城,6=>教学视频,7=>本命预测,8=>vip会员
     * order_id 01=>校准生辰 02=>运势 03=>幸运之城，04=>教学视频，05=>本命预测
     * @return Json
     * @throws Exception
     */
    public function pay_unlock()
    {
        $this->msg = '';
        $this->CheckUserTel();
        $param['trade_type'] = input('param.trade_type/d', 0);
        $param['order_type'] = input('param.order_type/d', 0);
        $param['gids'] = input('param.gids/s', '');
        $param['param'] = input('param.param', '');
        $param['openid'] = input('param.openid/s', '');
        $param = OrdersLib::pay_order_param_format($this->user['id'], $param);
        if ($this->msg)
        {
            Log::write('v13下单请求参数有误：' . $this->msg, 'notice', true);
            return show(config('code.error'), $this->msg);
        }
        if ($param['price'] >= 0.01)
        {
            //生成订单数据并下单
            $arr = $this->SaveOrder($param);
            return show(config('code.success'), '下单成功', $arr['data']);
        }
        return show(config('code.error'), '下单金额错误');
    }

    /**
     * 接口，免费下单
     * @throws ApiException
     * @throws Exception
     */
    public function free_pay_unlock()
    {
        $this->msg = '';
        $this->CheckUserTel();
        $param['trade_type'] = input('param.trade_type/d', 0);
        $param['order_type'] = input('param.order_type/d', 0);
        $param['gids'] = input('param.gids/s', '');
        $param['param'] = input('param.param', '');
        $param['password'] = input('param.password', '');
        $param['openid'] = input('param.openid/s', '');
        $param = OrdersLib::pay_order_param_format($this->user['id'], $param, true);
        if ($this->msg)
        {
            Log::write('v13免费下单请求参数有误：' . $this->msg, 'notice', true);
            return show(config('code.error'), $this->msg);
        }
        if ($param['price'] <= 0)
        {
            //使用免费券或支付金额小于0
            $data = $this->SaveFreeOrder($param);
            $distinctId = $this->request->header('distinct-id', '');
            if ($distinctId)
            {
                #神策打点 确认订单
                (new \app\common\service\Orders())->getSensorsTrackData($data, 'buy_confirm');
                #神策打点 免费支付成功
                (new \app\common\service\Orders())->getSensorsTrackData($data, 'buy_success');
            }
            return show(config('code.success'), '下单成功', ['order_id' => $data]);
        }
        return show(config('code.error'), '下单金额有误');
    }

    /**
     * 运势下单
     * @param int $rid
     * @param int $start_time
     * @param int $order_type
     * @return bool|int|string
     */
    private function pay_fortune($rid, $start_time, $order_type)
    {
        $arr = [
            'type' => $order_type - 1,
            'rids' => $rid,
            'time' => $start_time,
            'create_time' => $this->request->time(),
        ];
        try
        {
            $fid = (new Fortune())->insertGetId($arr); //每日运势id
        }
        catch (Exception $e)
        {
            return false;
        }

        return $fid;
    }

    /**
     * 添加中间表数据
     * @param $rid
     * @param $gids
     * @param $oid
     * @return bool
     */
    private function insertMiddle($rid, $gids, $oid)
    {
        $array = [];
        foreach ($gids as $k => $v)
        {
            $array[] = [
                'gid' => $v,
                'oid' => $oid,
                'rid' => $rid
            ];
        }
        //中间表
        try
        {
            (new OrdersGoods())->insertAll($array);
        }
        catch (Exception $e)
        {
            return false;
        }

        return true;
    }

    /**
     * 会员下单
     * @param $orders
     * @param $gid
     * @return bool
     */
    private function pay_vip($orders, $gid)
    {
        return OrdersLib::UpdateVipStatus($orders, $gid);
    }

    /**
     * 生成订单，并下单
     * @param $param ['order_type','trade_type','rid','cid','reid','gids','goods_info','price'，'start_time','out_trade_no','account','extend','pay_des','openid']
     * @return array|bool|Json
     * @throws Exception
     */
    private function SaveOrder($param)
    {
        $middle_res = true;
        $CouponModel = new UserCoupon();
        $orderModel = new OrdersCacheModel();
        Db::startTrans();
        try
        {
            //若是运势，则添加运势中间表数据
            if (in_array($param['order_type'], [2, 3, 4]))
            {
                $middle_res = $this->pay_fortune($param['rid'], $param['start_time'], $param['order_type']);
            }
            if ($middle_res == false)
            {
                throw new ApiException('下单失败,请重新操作');
            }
            //生成订单数据
            $insert = [
                'order_type' => $param['order_type'],
                'uid' => $this->user['id'],
                'gid' => $param['gids'][0],
                'order_id' => $param['out_trade_no'],
                'reid' => $param['reid'],
                'fid' => $middle_res,
                'trade_type' => $param['trade_type'],
                'total_amount' => $param['price'],
                'create_time' => $this->request->time(),
                'status' => 0,
                'account' => $param['account'],
                'extend' => $param['extend']
            ];
            // 生成订单到数据库
            try
            {
                //生成订单数据
                $oid = $orderModel->SaveData($insert);
                if ($oid === false)
                {
                    throw new ApiException('下单失败,请重新操作');
                }
                //添加中间表数据
                if ($param['rid'])
                {
                    $middle_res = $this->insertMiddle($param['rid'], $param['gids'], $oid);
                    if ($middle_res === false)
                    {
                        throw new ApiException('下单失败,请重新操作');
                    }
                }
            }
            catch (Exception $e)
            {
                Log::write('订单入库失败：' . $e->getMessage() . '【' . $e->getFile() . $e->getLine() . '】', 'error');
            }
            //修改优惠券状态为已锁定
            if ($param['cid'])
            {
                $res = $CouponModel->use_return($this->user['id'], $param['cid'], ['status' => 4, 'oid' => $oid, 'update_time' => $this->request->time()]);
                if ($res === false)
                {
                    throw new ApiException($CouponModel->getError());
                }
            }
            //检测订单关闭入队
            PushQueue::CloseOrder($param['out_trade_no']);

            //更新订单详情缓存
            $orderModel->UpdateCache($param['out_trade_no'], 0);
            Db::commit();
        }
        catch (Exception $e)
        {
            Db::rollback();
            Log::write('入库失败信息：' . $e->getMessage() . '【' . $e->getFile() . $e->getLine() . '】', 'error');
            throw new ApiException('下单失败,请重新操作');
        }

        //支付订单
        $arr = OrdersLib::unifyPayOrder([
            'oid' => $oid,
            'trade_type' => $param['trade_type'],
            'total_amount' => $param['price'],
            'pay_des' => $param['pay_des'],
            'order_id' => $param['out_trade_no'],
            'openid' => $param['openid'],
            'callback_url' => '',
            'order_type' => $param['order_type']
        ], 1);
        $new_gid = [];
        foreach ($param['gids'] as $gid)
        {
            $new_gid[] = 'apple_pay_' . $gid;
        }
        $skuId = implode(',', $new_gid);

        if ($this->headers['app-type'] == 'ios')
        {
            $arr['data']['skuId'] = $skuId;
        }
        return $arr;
    }

    /**
     * 生成订单数据并入队
     * @param $param [cid,rid,start_time,order_type,gids,out_trade_no,reid,extend,goods_info]
     * @return string
     * @throws ApiException
     * @throws Exception
     */
    private function SaveFreeOrder($param)
    {
        $middle_res = true;
        $CouponModel = new UserCoupon();
        $now_time = $this->request->time();
        $gid = (int)(current($param['gids']));
        //订单状态
        $status = OrdersLib::getOrderStatus($param['gids'], $param['order_type']);
        Db::startTrans();
        try
        {
            (new Recode())->UpdateData($this->user['id'], $param['rid'], [], 1);//or_day生成
            //若是运势，则添加运势中间表数据
            if (in_array($param['order_type'], [2, 3, 4], true))
            {
                $middle_res = $this->pay_fortune($param['rid'], $param['start_time'], $param['order_type']);
            }
            if ($middle_res == false)
            {
                throw new ApiException('下单失败,请重新操作');
            }
            //生成订单数据
            $insert = [
                'order_type' => $param['order_type'],
                'uid' => $this->user['id'],
                'gid' => $gid,
                'order_id' => $param['out_trade_no'],
                'reid' => $param['reid'],
                'fid' => $middle_res === true ? 0 : $middle_res,
                'trade_type' => $param['trade_type'],
                'total_amount' => 0,
                'create_time' => $now_time,
                'update_time' => $now_time,
                'pay_time' => $now_time,
                'status' => $status,
                'account' => 0,
                'extend' => $param['extend']
            ];
            // 生成订单到数据库
            $OrdersCacheModel = new OrdersCacheModel();
            //生成订单数据
            $oid = $OrdersCacheModel->SaveData($insert);
            if ($oid === false)
            {
                throw new ApiException('下单失败,请重新操作');
            }
            //添加中间表数据
            if ($param['rid'])
            {
                $middle_res = $this->insertMiddle($param['rid'], $param['gids'], $oid);
                if ($middle_res === false)
                {
                    throw new ApiException('下单失败,请重新操作');
                }
            }
            //商品购买人数自增,教学视频和本命报告根据课程进行缓存数据
            if (in_array($param['order_type'], [6, 7], true))
            {
                $OrdersCacheModel->SaveTotalPrepaidOrder($param['order_type'], $gid);
            } elseif ($param['order_type'] === 17)
            {   // 合盘报告 根据gid自增 和gid与关系ID【relation_id】新增 维护两个缓存
                $extend = \GuzzleHttp\json_decode($param['extend'], true);
                $OrdersCacheModel->SaveTotalPrepaidOrder($param['order_type'], $extend['synastry_report']['srid']); // 根据srid自增
                $OrdersCacheModel->SaveTotalPrepaidOrder($param['order_type'], $extend['synastry_report']['srid'], $extend['synastry_report']['relation_id']); // 根据srid与关系ID【relation_id自增
            } else
            {
                $OrdersCacheModel->SaveTotalPrepaidOrder($param['order_type'], 0);
            }

            //修改优惠券状态为已锁定
            if ($param['cid'])
            {
                $res = $CouponModel->use_return($this->user['id'], $param['cid'], ['status' => 1, 'oid' => $oid, 'update_time' => $this->request->time()]);
                if ($res === false)
                {
                    throw new ApiException($CouponModel->getError());
                }
            }

            //生成第三方数据和入队
            switch (true)
            {
                case $param['order_type'] === 1://校准生辰入队
                    $this->RecQueue($param['reid'], $oid, $param['out_trade_no']);
                    break;
                case in_array($param['order_type'], [3, 4], true)://运势入队
                    $this->FortuneQueue($this->user['id'], $oid);
                    break;
                case $param['order_type'] === 5://地图入队
                    (new PushQueue())->Map($param['out_trade_no']);
                    break;
                case $param['order_type'] === 7://本命预测入队
                    $this->NatalQueue($param['rid'], $param['gids'], $param['out_trade_no']);
                    break;
                case $param['order_type'] === 8://若是vip，更新vip有效期和生效状态
                    $middle_res = $this->pay_vip($insert, $gid);
                    break;
                case $param['order_type'] === 15://定制报告入队
                    $questionModel = new ZlcrCustomReportQuestion();
                    //问题入队
                    $questionModel->orderReportQueue($insert['order_id']);
                    break;
                case $param['order_type'] === 16 : //修改塔罗记录状态
                    $extend = json_decode($insert['extend'], true);
                    $taroId = $extend['history']['id'];
                    (new ZlTarotRecords())->updateData($taroId, ['status' => 1]);
                    break;
                case $param['order_type'] === 17:
                    $this->SynastryQueue($insert, (int)$gid, null);
                    break;
            }
            //更新星力值
            if ($param['order_type'] !== 8)
            {   // VIP订单除外 更新星力值，  VIP星力值已经更新过了，禁止重复更新
                OrdersLib::UpdateVipBoon($insert, $gid, true);
            }
            if ($middle_res == false)
            {
                throw new ApiException('下单失败,请重新操作');
            }
            //塔罗记录更新订单编号数据
            if ($param['order_type'] === 16)
            {
                (new ZlTarotRecords())->updateData($param['history_id'], ['order_num' => $param['out_trade_no']]);
            }

            //更新订单详情缓存
            $OrdersCacheModel->UpdateCache($param['out_trade_no'], $status);
            Db::commit();
        }
        catch (Exception $e)
        {
            Db::rollback();
            throw new ApiException('下单失败,请重新操作');
        }
        // 开盲盒任务判断
        (new ZlActivePrizeNumIncRecord())->goodsTask($this->user['id'], $gid, $param['out_trade_no']);

        return $param['out_trade_no'];
    }

    /**
     * 校准生辰入队
     * @param $reid
     * @param $oid
     * @param $out_trade_no
     * @throws Exception
     */
    private function RecQueue($reid, $oid, $out_trade_no)
    {
        (new PushQueue())->Rectification($this->user, $reid, $oid, $out_trade_no);
    }

    /**
     * 运势入队
     * @param $uid
     * @param $oid
     * @return bool|mixed
     * @throws Exception
     */
    private function FortuneQueue($uid, $oid)
    {
        return (new PushQueue)->Fortune(['uid' => $uid, 'oid' => $oid]);
    }

    /**
     * 本命预测入队加结果数据写入
     * @param int $rid
     * @param array $gids
     * @param string $order_id
     * @throws Exception
     */
    private function NatalQueue($rid, $gids, $order_id)
    {
        $NatalReportModel = new NatalReport();
        $NatalReportModel->SaveQueue($this->user['id'], $rid, $gids, $order_id);
    }

    /**
     * 本命预测入队加结果数据写入
     * @param array $orders
     * @param int $unlock_gid
     * @param null $queueDelay 队列延迟时间
     * @throws Exception
     */
    private function SynastryQueue(array $orders, int $unlock_gid, $queueDelay = null)
    {
        $extend = json_decode($orders['extend'], true);
        (new ZlSynastryReport())->SaveQueue($this->user['id'], $unlock_gid, $extend['synastry_report'], $orders['order_id'], $queueDelay);
    }
}
